package com.sise.recomder;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sise.bean.PurchaseRecordBean;
import com.sise.entity.*;
import com.sise.mapper.*;
import net.librec.common.LibrecException;
import net.librec.conf.Configuration;
import net.librec.data.DataModel;
import net.librec.data.model.TextDataModel;
import net.librec.filter.GenericRecommendedFilter;
import net.librec.recommender.Recommender;
import net.librec.recommender.RecommenderContext;
import net.librec.recommender.item.RecommendedItem;
import net.librec.similarity.PCCSimilarity;
import net.librec.similarity.RecommenderSimilarity;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;

/**
 * @author zj
 */
@Service
public class PublicUse {

    @Resource
    private RatingMapper ratingMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private ProductInfoMapper productInfoMapper;

    @Resource
    private OrderMasterMapper orderMasterMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    /**
     * @return 获取所有用户列表
     */
    public List<User> getUserList() {
        return userMapper.selectList(null);
    }

    /**
     * @return 获取所有菜品列表
     */
    public List<ProductInfo> getProductInfoList() {
        return productInfoMapper.selectList(null);
    }

    /**
     * @param openId openId
     * @return 获取openId的购买列表
     */
    public List<PurchaseRecordBean> queryOpenIdPurchaseList(String openId) {
        List<PurchaseRecordBean> purchaseRecordBeanList = new ArrayList<>();
        QueryWrapper<OrderMaster> orderMasterQueryWrapper = new QueryWrapper<>();
        orderMasterQueryWrapper.lambda().eq(OrderMaster::getOpenId, openId);
        List<OrderMaster> orderMasters = orderMasterMapper.selectList(orderMasterQueryWrapper);
        for (OrderMaster orderMaster :
                orderMasters) {
            QueryWrapper<OrderDetail> orderDetailQueryWrapper = new QueryWrapper<>();
            orderDetailQueryWrapper.lambda().eq(OrderDetail::getOrderId, orderMaster.getOrderId());
            List<OrderDetail> orderDetails = orderDetailMapper.selectList(orderDetailQueryWrapper);
            for (OrderDetail orderDetail :
                    orderDetails) {
                purchaseRecordBeanList.add(new PurchaseRecordBean()
                        .setOrderDetailId(orderDetail.getOrderDetailId())
                        .setOpenId(orderMaster.getOpenId())
                        .setProductId(orderDetail.getProductId()));
            }
        }
        return purchaseRecordBeanList;
    }

    /**
     * @return 预处理列表
     */
    public TreeSet<ProductInfo> preprocessingList() {
        TreeSet<ProductInfo> preList = new TreeSet<>((o1, o2) -> {
            if (o1.getSimilarity() != o2.getSimilarity())
                return (int) (o1.getSimilarity() - o2.getSimilarity()) * 100;
            else
                return o1.getProductLikeCount() - o2.getProductLikeCount();
        });
        return preList;
    }

    /**
     * @param preList
     * @return 生成的推荐结果
     */
    public List<ProductInfo> generateRecommendationResults(TreeSet<ProductInfo> preList) {
        ArrayList<ProductInfo> recomLists = new ArrayList<>();
        for (int i = 0; preList.size() > 0 && i < 5; i++) {
            recomLists.add(preList.pollLast());
            preList.pollLast();
        }
        if (recomLists.size() < 5) {
            //推荐数量不满5个, 补足喜欢数最高的菜品
            //List<ProductInfo> topNProductInfo = productInfoMapper.findTopNProductInfo(5);
            //推荐数量不满5个, 随机补足菜品
            List<ProductInfo> topNProductInfo = productInfoMapper.randomlyGenerateNProductInfo(5);
            for (int i = 0; i < 5; i++) {
                if (!recomLists.contains(topNProductInfo.get(i))) {
                    recomLists.add(topNProductInfo.get(i));
                }
            }
        }
        return recomLists;
    }

    /**
     * librec推荐
     *
     * @param properties
     * @param recommender
     * @return
     * @throws LibrecException
     */
    public List<RecommendedItem> recomder(String properties, Recommender recommender) {

        // 推荐配置
        Configuration conf = new Configuration();
        conf.set("dfs.data.dir", "src/main/resources/data");
        conf.set("data.input.path", "train");
        Configuration.Resource resource = new Configuration.Resource("rec/" + properties);
        conf.addResource(resource);

        // 建立数据模型
        DataModel dataModel = new TextDataModel(conf);
        try {
            dataModel.buildDataModel();
        } catch (LibrecException e) {
            e.printStackTrace();
        }


        // 设置推荐上下文
        RecommenderContext context = new RecommenderContext(conf, dataModel);
        RecommenderSimilarity similarity = new PCCSimilarity();
        similarity.buildSimilarityMatrix(dataModel);
        context.setSimilarity(similarity);

        // 训练
        recommender.setContext(context);
        try {
            recommender.recommend(context);
        } catch (LibrecException e) {
            e.printStackTrace();
        }

        List<String> userIdList = new ArrayList<>();
        List<String> itemIdList = new ArrayList<>();

        //推荐结果
        List<RecommendedItem> recommendedItemList = recommender.getRecommendedList();
        GenericRecommendedFilter filter = new GenericRecommendedFilter();
        filter.setUserIdList(userIdList);
        filter.setItemIdList(itemIdList);
        return recommendedItemList;
    }

    /**
     * 显示推荐数据
     *
     * @param recommendedItemList
     */
    public void printRecommender(List<RecommendedItem> recommendedItemList) {
        System.out.println("推荐个数：" + recommendedItemList.size());
        for (RecommendedItem recommendedItem : recommendedItemList) {
            System.out.println(
                    "user:" + recommendedItem.getUserId() + " "
                            + "item:" + recommendedItem.getItemId() + " "
                            + "value:" + recommendedItem.getValue()
            );
        }
    }

    /**
     * 将txt数据写到Mysql
     */
    public void Reader() {
        File file;
//        try {
//            // 线上使用路径
//            file = ResourceUtils.getFile("classpath:data/train/data_set.txt");
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }
        BufferedReader reader = null;
        try {
            file = new File("src/main/resources/data/train/data_set.txt");
            reader = new BufferedReader(new FileReader(file));
            String tempStr;
            while ((tempStr = reader.readLine()) != null) {
                String[] s = tempStr.split(" ");
                QueryWrapper<Rating> ratingQueryWrapper = new QueryWrapper<>();
                ratingQueryWrapper.lambda().eq(Rating::getUser, s[0]).eq(Rating::getItem, s[1]);
                Rating rating = ratingMapper.selectOne(ratingQueryWrapper);
                rating.setItemValue(s[2]);
                ratingMapper.updateById(rating);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    /**
     * 将Mysql读到txt
     */
    public void Writer() {
        List<Rating> ratingList = ratingMapper.selectList(null);
        File file;
        BufferedWriter bw = null;
        try {
//            线上使用路径
//            file = ResourceUtils.getFile("classpath:data/train/data_set.txt");
            file = new File("src/main/resources/data/train/data_set.txt");
            if (!file.exists()) {
                file.createNewFile();
            }
            bw = new BufferedWriter(new FileWriter(file));
            for (Rating rating :
                    ratingList) {
                bw.write(rating.getUser() + " " +
                        rating.getItem() + " " +
                        rating.getItemRating() + "\r\n");
            }
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bw != null) {
                try {
                    bw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

}
